package cn.gene.timeyan.ums.webapi.ums.utils;

import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

/**
 * 包含自定义md5加密方法，注册时各字段的合法性校验方法以及验证码发送到邮箱和短信的方法*
 *
 * @author LWG
 * @date 2022/8/2 16:18
 * @since 1.0.0 @gene.cn
 */
@Component
public class UserUtil {
    @Autowired(required = false)
    private JavaMailSenderImpl mailSender;

    /**
     * 短信发送相关信息
     */
    @Value("${sms.secretID}")
    private String secretID;
    @Value("${sms.secretKey}")
    private String secretKey;
    @Value("${sms.appID}")
    private String appID;
    @Value("${sms.signName}")
    private String signName;
    @Value("${sms.templateID}")
    private String templateID;
    @Value("${sms.validTime}")
    private String validTime;


    /**
     * 发送验证码到用户邮箱，并返回生成的验证码
     *
     * @param sendTo 用户邮箱
     * @return 生成的验证码
     */
    public String sendValidEMail(String sendTo) {
        SimpleMailMessage message = new SimpleMailMessage();
        String code = generateValidCode();
        message.setSubject("环绿回收验证码");
        message.setText("您正在重置您的密码，若非本人操作请无视。\n 验证码：" + code +
                "\n 验证码请勿告知他人，该验证码将在三十分钟后失效。");
        message.setTo(sendTo);
        message.setFrom("1215683942@qq.com");
        mailSender.send(message);
        return code;
    }

    /**
     * 发送验证码到用户手机，并返回生成的验证码
     *
     * @param sendTo 用户手机号
     * @return 生成的验证码
     */
    public String sendValidSms(String sendTo) {
        String code = generateValidCode();

        try {
            // 实例化一个认证对象，入参需要传入腾讯云账户secretId，secretKey,此处还需注意密钥对的保密
            Credential cred = new Credential(secretID, secretKey);
            HttpProfile httpProfile = new HttpProfile();

            //实例化一个客户端配置对象,这个配置可以进行签名（使用私钥进行加密的过程），对方可以利用公钥进行解密
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);

            // 实例化要请求产品的client对象,clientProfile是可选的
            SmsClient client = new SmsClient(cred, "ap-guangzhou");
            // 实例化一个请求对象,每个接口都会对应一个request对象
            SendSmsRequest req = new SendSmsRequest();
            String[] phoneNumberSet1 = {"+86" + sendTo};
            req.setPhoneNumberSet(phoneNumberSet1);
            req.setSmsSdkAppId(appID);
            req.setSignName(signName);
            req.setTemplateId(templateID);

            String[] templateParamSet1 = {code, validTime};
            req.setTemplateParamSet(templateParamSet1);

            // 返回的resp是一个SendSmsResponse的实例，与请求对象对应
            SendSmsResponse resp = client.SendSms(req);
            // 输出json格式的字符串回包
            System.out.println(SendSmsResponse.toJsonString(resp));
        } catch (TencentCloudSDKException e) {
            System.out.println(e.toString());
        }
        return code;
    }

    /**
     * 生成验证码
     *
     * @return
     */
    private String generateValidCode() {
        Random random = new Random();
        int i = random.nextInt() * 10000;
        return String.valueOf(i).substring(1, 5);
    }

    /**
     * 使用MD5来实现对密码的单向加密，之后再截取一半加密后的密码进行md5加密，最终生成48位密文，
     * 加密算法为单向，且无法使用通用的彩虹表反推密码，提高安全性
     *
     * @param password
     * @return 加密后的密文
     * @throws NoSuchAlgorithmException
     */
    public String encryptByMD5(String password) {
        StringBuilder stringBuilder = new StringBuilder();

        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        md5.update(password.getBytes(StandardCharsets.UTF_8));
        byte[] temp1 = md5.digest();
        //将密文转为十六进制后存储入string
        for (byte b : temp1) {
            stringBuilder.append(String.format("%02x", new Integer(b & 0xff)));
        }
        String temp1_s = stringBuilder.toString();
        //清空该builder以及MessageDigest等待下次使用
        stringBuilder.delete(0, stringBuilder.length());
        md5.reset();

        //再次加密
        md5.update(temp1_s.substring(16).getBytes(StandardCharsets.UTF_8));
        byte[] temp2 = md5.digest();
        //将密文转为string
        for (byte b : temp2) {
            stringBuilder.append(String.format("%02x", new Integer(b & 0xff)));
        }
        String temp2_s = stringBuilder.toString();

        return temp1_s.substring(0, 16) + temp2_s;
    }

    /**
     * 通过该方法判断字符串是否都是数字构成
     * @param str
     * @return
     */
    public boolean isNumeric(String str) {
        for (int i = str.length(); --i >= 0; ) {
            if (!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }
}

